<!--
 * @Description: 
 * @Version: **
 * @Author: wurangkun
 * @Date: 2023-01-20 15:24:21
 * @LastEditors: Please set LastEditors
 * @LastEditTime: 2023-02-01 17:10:34
-->
<template>
  <!-- <backgroundImage :app="app"></backgroundImage> -->
  <div ref="page_canvas" id="page_canvas"></div>
  <startGame @start="start" @restart="restart" :status="status"></startGame>
</template>

<script setup>
import * as PIXI from "pixi.js";
// import backgroundImage from "./backgroundImage.vue"
import startGame from "./startGame.vue"
import { onMounted, onUnmounted, reactive, ref } from "vue";
import map from '@/assets/icon/map.jpg'
import bulletImg from '@/assets/icon/bunny-self.png'
import Candle from '@/assets/icon/candle.png'
import EnemyIcon from '@/assets/icon/enemy.png'
import ChristmasGift from '@/assets/icon/christmas-gift.png'
import Fruit from '@/assets/icon/fruit.png'
import Snowflake from '@/assets/icon/snowflake.png'
import Stockings from '@/assets/icon/stockings.png'
import SmallBell from '@/assets/icon/small-bell.png'
import Glove from '@/assets/icon/glove.png'
import Snowman from '@/assets/icon/snowman.png'
import Tree from '@/assets/icon/tree.png'
import Cap from '@/assets/icon/cap.png'
import Candies from '@/assets/icon/candies.png'
import Cup from '@/assets/icon/cup.png'
import DeerHead from '@/assets/icon/deer-head.png'
import Coffee from '@/assets/icon/coffee.png'
import PieDoll from '@/assets/icon/pie-doll.png'
import BallShaped from '@/assets/icon/ball-shaped.png'
import plane from '@/assets/icon/plane.png'

let app = null

let gaming = false
let isReady = false
let status = ref('start')
// 画布

let page = null
let width = null
let height = null
// 飞机实例
let aircraft = null

//子弹数组
let bullets = []

// 敌机数组
let enemiesList = []

// 敌机 移动速度 
const enemySpeed = 4
// 敌机生产速度
const enemyTimer = 2000
// 子弹生产速度
const BulletTimer = 500
// 子弹 移动速度 
const BulletSpeed = 5

//飞机配置
const aricraftConfig = reactive({
  height: 80,
  width: 60
})

const metaList = [
  { name: 'Enemy', url: EnemyIcon, life: 5, enemySpeed: 2 },
  { name: 'Candle', url: Candle },
  { name: 'ChristmasGift', url: ChristmasGift },
  { name: 'Fruit', url: Fruit },
  { name: 'Snowflake', url: Snowflake },
  { name: 'Stockings', url: Stockings },
  { name: 'SmallBell', url: SmallBell },
  { name: 'Glove', url: Glove },
  { name: 'Snowman', url: Snowman },
  { name: 'Tree', url: Tree },
  { name: 'Cap', url: Cap },
  { name: 'Candies', url: Candies },
  { name: 'Cup', url: Cup },
  { name: 'DeerHead', url: DeerHead },
  { name: 'Coffee', url: Coffee },
  { name: 'BallShaped', url: BallShaped },
  { name: 'PieDoll', url: PieDoll }
]

const loader = PIXI.Loader.shared;

onMounted(() => {
  // gaming = true // 开始游戏
  app = createCanvas() // 创建画布
  setTimeout(() => {
    // 创建飞机
    setBg()
  }, 100);
  setTimeout(() => {
    // 创建飞机
    setBg2()
  }, 200);
  setTimeout(() => {
    setAircraft()
  }, 500);

  page.appendChild(app.view) // 将画布添加到盒子中
  isReady = true
  console.log('ready');
  setInterval(() => {// 定时添加敌机
    if (gaming) {
      setEnemies()
    }
  }, enemyTimer);

  setInterval(() => {// 创建子弹
    if (gaming) {
      setBullets()
    }
  }, BulletTimer);

  useFighting()// 设置战斗逻辑
})

onUnmounted(() => {
  clearInterval()
  app = null
})

//创建画布
const createCanvas = () => {
  page = document.getElementById('page_canvas') // 获取画布盒子
  width = page.offsetWidth
  height = page.offsetHeight
  return new PIXI.Application({ width: width, height: height, transparent: true })
}

//开始游戏
const start = () => {
  let y = app.screen.height - aricraftConfig.height  // 设置开始时 飞机移动距离
  app.ticker.add(move);
  function move (delta) {
    if (y < aircraft.y) { // 当飞机移动到指定位置时,开始游戏
      aircraft.y -= 2 * delta;
    } else {
      app.ticker.remove(move);
      gaming = true
      status.value = 'start'
    }
  }
}

// 重新开始
const restart = () => {
  aircraft.x = app.screen.width / 2;
  aircraft.y = app.screen.height + aricraftConfig.height
  start()
}

// 创建背景
const setBg = () => {
  const bg1 = { name: 'bg1', url: map }
  loader.add(bg1).load((_, resources) => { // 将背景图片添加到画布舞台中,并且为其添加配置和事件
    const bg = new PIXI.Sprite(resources['bg1'].texture); // 创建精灵图
    bg.anchor.set(0, 0); //设定中心锚点为中间
    bg.x = 0; //将位置设置为中间  
    bg.y = 0;
    bg.width = page.offsetWidth
    bg.height = page.offsetHeight
    // 背景移动
    app.ticker.add((delta) => {
      if (gaming) {
        if (bg.y * -1 >= bg.height) {
          console.log(bg.y * -1 - bg.height);
          bg.y = page.offsetHeight
        } else {
          bg.y -= 2 * delta
        }
      }
    })
    app.stage.addChild(bg);//将精灵贴图放进舞台中
  })
}
// 创建背景
const setBg2 = () => {
  const bg2 = { name: 'bg2', url: map }
  loader.add(bg2).load((_, resources) => { // 将背景图片添加到画布舞台中,并且为其添加配置和事件
    const bg = new PIXI.Sprite(resources['bg2'].texture); // 创建精灵图
    bg.anchor.set(0, 0);//设定中心锚点为中间
    bg.x = 0;//将位置设置为中间  
    bg.y = page.offsetHeight;
    bg.width = page.offsetWidth
    bg.height = page.offsetHeight
    // 背景移动
    app.ticker.add((delta) => {
      if (gaming) {
        if (bg.y * -1 >= bg.height) {
          const diff = bg.y * -1 - bg.height
          console.log(diff);
          bg.y = page.offsetHeight
        } else {
          bg.y -= 2 * delta
        }
      }
    })
    app.stage.addChild(bg);//将精灵贴图放进舞台中
  })
}

// 创建飞机
const setAircraft = () => {
  const img = { name: 'aircraft', url: plane } // 设置飞机图片
  loader.add(img).load((_, resources) => { // 将飞机图片添加到画布舞台中,并且为其添加配置和事件
    aircraft = new PIXI.Sprite(resources['aircraft'].texture); // 创建精灵图
    aircraft.anchor.set(0.5, 0.5);//设定中心锚点为中间
    aircraft.x = app.screen.width / 2;//将位置设置为中间  
    aircraft.y = app.screen.height + aricraftConfig.height;
    aircraft.width = aricraftConfig.width
    aircraft.height = aricraftConfig.height
    aircraft.interactive = true // 是否允许交互
    // 拖拽飞机
    dragPlane()
    app.stage.addChild(aircraft);//将精灵贴图放进舞台中
  })
}

// 拖拽飞机
const dragPlane = () => {
  let startPoint = null // 拖动时开始点
  let dragFlag = false  // 是否在拖动

  //拖拽事件开始
  aircraft.on('pointerdown', (e) => {
    dragFlag = true
    // 将当前点设置为移动开始点
    startPoint = { x: e.data.global.x, y: e.data.global.y }
  })

  aircraft.on('pointermove', (e) => {
    if (!gaming) return
    // 当正在移动时,获取当前鼠标位置 与 开始拖动的点的位置进行比较,更改点的位置,进行位移.并且将开始点设置为改变之后的值
    if (dragFlag) {
      let x = aircraft.x + e.data.global.x - startPoint.x;
      let y = aircraft.y + e.data.global.y - startPoint.y;
      if (x >= width - aricraftConfig.width / 2 || x <= aricraftConfig.width / 2) {
        x = aircraft.x
      } else if (y <= aricraftConfig.height / 2 || y >= height - aricraftConfig.height / 2) {
        y = aircraft.y
      }
      aircraft.x = x; //更改
      aircraft.y = y;
      startPoint = { x: e.data.global.x, y: e.data.global.y }
    }
  })
  aircraft.on('pointerup', (e) => {
    dragFlag = false
  })
}

//创建子弹
const setBullets = () => {
  const name = 'bullet' + Number(new Date())
  app.loader.add({ name: name, url: bulletImg }).load((_, resources) => { // 将子弹图片添加到画布舞台中,并且为其添加配置和事件'
    const bullet = new PIXI.Sprite(resources[name].texture); // 创建精灵图
    bullet.anchor.set(0.5, 0.5);//设定中心锚点为中间
    bullet.x = aircraft.x;//将位置设置为中间
    bullet.y = aircraft.y - (aircraft.height / 2);
    bullet.width = 30
    bullet.height = 40
    bullet.interactive = true // 是否允许交互
    app.ticker.add(function (delta) {//delta为增量时间
      bullet.y -= BulletSpeed * delta;
    });
    bullets.push(bullet)
    app.stage.addChild(bullet);//将精灵贴图放进舞台中
  })
}

//创建敌机
const setEnemies = () => {
  const index = Math.floor(Math.random() * 15)
  const item = metaList[index]
  const name = item.name + Number(new Date())  //随机生成敌机 将name加上时间戳保证 生成的key不冲突
  loader.add({ name: name, url: item.url }).load((_, resources) => { // 将敌机图片添加到画布舞台中,并且为其添加配置和事件'
    const enemy = new PIXI.Sprite(resources[name].texture); // 创建精灵图
    enemy.anchor.set(0.5, 0.5);//设定中心锚点为中间
    const x = Math.random() * (app.screen.width - 40) + 40
    enemy.x = x; // 将位置设置为中间
    enemy.y = 0;
    enemy.width = 80
    enemy.height = 80
    enemy.life = item.life || 1 // 敌机血量
    enemy.delta = Math.ceil(Math.random() * 10)
    enemy.interactive = true // 是否允许交互
    let flag = x < app.screen.width / 2 ? 1 : 0
    let first = true // 是否为第一次转向
    app.ticker.add(function (delta) { // delta为增量时间
      const speed = item.enemySpeed || enemySpeed // 设置自定义时间 否则为默认时间
      const step = speed * delta
      if (!first) {
        if (enemy.x <= 40) flag = 1
        else if (enemy.x >= app.screen.width - 40) flag = 0
      }
      if (flag) {
        enemy.x += step;
      } else {
        enemy.x -= step;
      }
      enemy.y += step;
      first = false
    });
    enemiesList.push(enemy)
    app.stage.addChild(enemy);//将精灵贴图放进舞台中
  })
}

// 战斗逻辑 计算碰撞体积
const useFighting = () => {
  app.ticker.add(() => {
    if (gaming) {
      // 碰撞检测 我方飞机和敌方飞机碰撞
      enemiesList.forEach((enemy, enemyIndex) => {
        if (hitTestObject(aircraft, enemy)) {
          // game over
          console.log('game over');
          gaming = false
          status.value = 'end'
        } else if (enemy.y > height + 100) {
          app.stage.removeChild(enemy);//将精灵贴图放进舞台中
          enemiesList.splice(enemyIndex, 1)
        }
      })
      // 遍历敌军和我方子弹
      enemiesList.forEach((enemy, enemyIndex) => {
        bullets.forEach((bullet, bulletIndex) => {
          if (hitTestObject(enemy, bullet)) {
            enemy.life-- // 血量减一
            if (enemy.life == 0) { // 血量清空时,销毁敌机
              enemiesList.splice(enemyIndex, 1)
              app.stage.removeChild(enemy);
            }
            bullets.splice(bulletIndex, 1)
            app.stage.removeChild(bullet);
          }
        })
      })
    } else {
      enemiesList.forEach((enemy, enemyIndex) => {
        app.stage.removeChild(enemy);
      })
      bullets.forEach((bullet, bulletIndex) => {
        app.stage.removeChild(bullet);
      })
      enemiesList = []
      bullets = []
    }
  })
}

// 碰撞检测
const hitTestObject = (objectA, objectB) => {
  return (objectA.x + objectA.width > objectB.x &&
    objectA.x < objectB.x + objectB.width &&
    objectA.y + objectA.height > objectB.y &&
    objectA.y < objectB.y + objectB.height)
}

</script>

